#pragma once

#include <iostream>
#include <pthread.h>
#include <functional>
#include "Sock.hpp"
#include "log.hpp"
#include "Protocol.hpp"

using namespace protocol_ns;
using func_t = std::function<Response(const Request &)>;
static const uint16_t default_port = 8889;

namespace tcp_server_ns
{
    class tcpServer;

    struct ThreadDate
    {
        ThreadDate(const int &sock, uint16_t &port, const std::string &ip, tcpServer *serv)
            : _sock(sock), _port(port), _ip(ip), _serv(serv)
        {
        }

        int _sock;
        uint16_t _port;
        std::string _ip;
        tcpServer *_serv;
    };

    class tcpServer
    {
    public:
        tcpServer(const func_t &func, const uint16_t port = default_port)
            : _port(port), _func(func)
        {
        }

        void InitServer()
        {
            _listensock.Socket();
            _listensock.Bind(_port);
            _listensock.Listen();

            LogMessage(Info, "Server init sucess, listensock: %d", _listensock.GetFd());
        }

        void Start()
        {
            while (true)
            {
                std::string client_ip;
                uint16_t client_port;

                int sock = _listensock.Accept(&client_ip, &client_port);
                if (sock < 0)
                    continue;

                ThreadDate *data = new ThreadDate(sock, client_port, client_ip, this);
                pthread_t th;
                pthread_create(&th, nullptr, ThreadRoutine, data);
            }
        }

        static void *ThreadRoutine(void *args)
        {
            pthread_detach(pthread_self());
            ThreadDate *data = static_cast<ThreadDate *>(args);

            data->_serv->ServiceIO(data->_sock, data->_ip, data->_port);
            delete data;
        }

        void ServiceIO(const int &sock, const std::string &ip, const uint16_t &port) // 由多线程调用
        {
            // inbuffer ?? 防止读到一半的数据被覆盖掉
            std::string inbuffer;
            while (true)
            {
                // 1. 如何保证读到了完整的报文 状态码标识
                std::string package;
                int n = ReadPackage(sock, inbuffer, &package);
                if (n < 0)
                {
                    break;
                }
                else if (n == 0)
                {
                    continue; // 如果读到的不是完整的报文，就将这次剩下的放在缓冲区中，然后加上下次读到的就是完整的报文
                }
                else
                {
                    // 2. 去掉有效载荷
                    package = RemoveHeader(package, n);
                    // 3. 假设已经读到了报文，做反序列化处理
                    Request req;
                    req.Deserialize(package);
                    // 4. 提取数据做业务处理
                    Response resp = _func(req);
                    // 5. 给用户做响应，序列化
                    std::string send_string;
                    resp.Serialize(&send_string);
                    // 6. 添加报头
                    send_string = AddHeader(send_string);
                    // 7. 发送到网络
                    send(sock, send_string.c_str(), send_string.size(), 0);

                    LogMessage(Info, "Send message success!");
                }
            }

            LogMessage(Info, "one client quit...");
        }

    private:
        Sock _listensock;
        uint16_t _port;
        func_t _func;
    };
}